package com.joymart.qualification.service;

import com.joymart.common.model.Range;
import com.joymart.common.system.BusinessConfig;
import com.joymart.common.system.IdGenerator;
import com.joymart.compute.model.MonthlyGroupPv;
import com.joymart.compute.service.MonthlyGroupPvService;
import com.joymart.qualification.model.AdvanceEvaluation;
import com.joymart.qualification.model.ManagerRetainEvaluation;
import com.joymart.qualification.model.RetainEvaluation;
import com.joymart.qualification.model.WhsAgentRetainEvaluation;
import com.joymart.user.model.BusinessRole;
import com.joymart.user.model.CachedUser;
import com.joymart.user.repo.BusinessRoleRepository;
import com.joymart.user.service.UserCacheManager;
import com.joymart.user.service.UserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

@Slf4j
@Service
public class RetainEvaluationService {

    @Autowired
    private BusinessConfig businessConfig;
    @Autowired
    private UserService userService;
    @Autowired
    private MonthlyGroupPvService monthlyGroupPvService;
    @Autowired
    private BusinessRoleRepository businessRoleRepository;
    @Autowired
    private UserCacheManager userCacheManager;
    @Autowired
    private AdvanceEvaluationService advanceEvaluationService;
    @Autowired
    private IdGenerator idGenerator;


    public void evaluateAll(Range range, BusinessRole businessRole) {
        List<String> userIds = new ArrayList<>();
        switch (businessRole) {
            case MANAGER -> userIds = businessRoleRepository.findByBusinessRole(BusinessRole.MANAGER);
            case AG_AGENT -> userIds = businessRoleRepository.findByBusinessRole(BusinessRole.AG_AGENT)
                    .stream()
                    .filter(id-> !userCacheManager.get(id).getBusinessRoles().contains(BusinessRole.MANAGER)) // 保住了经理资格的就不评估代理是否保级了
                    .filter(Objects::nonNull).collect(Collectors.toList());
            case AG_WHS -> userIds = businessRoleRepository.findByBusinessRole(BusinessRole.AG_WHS)
                    .stream()
                    .filter(id-> !userCacheManager.get(id).getBusinessRoles().contains(BusinessRole.AG_AGENT)) // 保住了代理资格的就不评估批发是否保级了
                    .filter(Objects::nonNull).collect(Collectors.toList());
        }

        List<RetainEvaluation> evaluations = userIds.stream().map(userCacheManager::get)
                .map(cu -> buildAndEvaluate(cu, range, businessRole))
                .filter(Objects::nonNull).toList();
        //这里一定不能一个 stream写下去，要先做完全部评估然后一并的降级。 边评估边降级. 容易产生计算错误。
        evaluations.forEach(this::apply);

    }

    /**
     * 构建保级评估对象
     * @param cachedUser
     * @param range
     * @param targetRole 只可以是 经理 银代理 银批发三个中的其一
     * @return
     */
    private RetainEvaluation buildAndEvaluate(CachedUser cachedUser, Range range, BusinessRole targetRole){

        if(!List.of(BusinessRole.AG_WHS, BusinessRole.AG_AGENT, BusinessRole.MANAGER).contains(targetRole)){
            log.warn("Business role {} is not applied for RetainEvaluation. Please check potential logic mistakes ", targetRole);
            return null;
        }

        if(targetRole == BusinessRole.MANAGER){
            AdvanceEvaluation managerEvaluation = advanceEvaluationService.evaluate(cachedUser.getId(), range, BusinessRole.MANAGER);
            return new ManagerRetainEvaluation(idGenerator.next(),managerEvaluation);
        }

        WhsAgentRetainEvaluation whsAgentRetainEvaluation = new WhsAgentRetainEvaluation();
        whsAgentRetainEvaluation.setUserId(cachedUser.getId());
        whsAgentRetainEvaluation.setEvaluateUser(cachedUser);
        whsAgentRetainEvaluation.setRange(range);
        whsAgentRetainEvaluation.setTargetRole(targetRole);
        List<MonthlyGroupPv> monthlyGroupPvList = monthlyGroupPvService.findMonthlyGroupPv(cachedUser, targetRole, range);
        List<WhsAgentRetainEvaluation.MonthlyStats> statsList = monthlyGroupPvList.stream().map(src -> {
            WhsAgentRetainEvaluation.MonthlyStats monthlyStats = new WhsAgentRetainEvaluation.MonthlyStats();
            monthlyStats.setMonth(src.getMonth());
            monthlyStats.setGroupPvSpec(targetRole == BusinessRole.AG_AGENT ? businessConfig.getAgentPvSpec()
                    : businessConfig.getWhsPvSpec());
            monthlyStats.setGroupPv(src.getAmount());
            return monthlyStats;
        }).toList();
        whsAgentRetainEvaluation.setMonthlyStatsList(statsList);
        return whsAgentRetainEvaluation;
    }

    /**
     * 应用评估结果
     * @param retainEvaluation
     */
    private void apply(RetainEvaluation retainEvaluation){
        if(retainEvaluation.isPassed()){
            return;
        }
        BusinessRole downgraded = null ;
        switch(retainEvaluation.getTargetRole()){
            case MANAGER -> downgraded = BusinessRole.AU_AGENT;
            case AG_AGENT -> downgraded = BusinessRole.AU_WHS;
            case AG_WHS -> downgraded = BusinessRole.AU_SHOP;
        }
        if(downgraded!=null){
            userService.modifyHighestRole(retainEvaluation.getEvaluateUser().getUser(), downgraded);
        }
    }



    /**
     * 由于产生了降级，需要重新评估哪些代理是银的。下同
     */
    public void recalculateAgAgent() {
        List<String> userIds = businessRoleRepository.findByBusinessRole(BusinessRole.AU_AGENT);
        userIds.stream().map(userCacheManager::get)
                .filter(cu->cu.getHighestRole() == BusinessRole.AU_AGENT)
                .filter(
                cu-> userCacheManager.downwardsSearchUntil(cu,
                        downstream->downstream.getBusinessRoles().contains(BusinessRole.AG_AGENT)
                ) ==null
        ).forEach(cu->userService.modifyHighestRole(cu.getUser(), BusinessRole.AG_AGENT));
    }

    public void recalculateAgWhs() {
        List<String> userIds = businessRoleRepository.findByBusinessRole(BusinessRole.AU_WHS);
        userIds.stream().map(userCacheManager::get)
                .filter(cu->cu.getHighestRole() == BusinessRole.AU_WHS)
                .filter(
                        cu-> userCacheManager.downwardsSearchUntil(cu,
                                downstream->downstream.getBusinessRoles().contains(BusinessRole.AG_WHS)
                        ) ==null
                ).forEach(cu->userService.modifyHighestRole(cu.getUser(), BusinessRole.AG_WHS));
    }
}
